#include <stdio.h>
#include <stdlib.h>

void mix_column(short * p_output);
void inv_mix_column(short * p_output);
short multiply_number_number(short num1, short num2);

int main(void)
{
	/*printf("Hex: %X, Dec: %d\r\n", 0xA, 0xA);*/
	short input[16] = {
	0x47, 0x40, 0xA3, 0x4C,
	0x37, 0xD4, 0x70, 0x9F,
	0x94, 0xE4, 0x3A, 0x42,
	0xED, 0xA5, 0xA6, 0xBC
	};
	inv_mix_column(input);
	register short counter = 0;
	while (counter < 16)
	{
		printf("%X\t", input[counter]);
		if ((counter+1) % 4 == 0) printf("\r\n");
		counter += 1;
	}
	return 0;
}

void mix_column(short * p_output)
{
	short time = 0; // used as a counter which is used to separate columns from input.
	short tempArray[4]; // used to hold each column from the input per time.
	while (time < 4)
	{
		short index = 0; // used as counter in various ways.
		while (index < 4)
		{
			tempArray[index] = p_output[time + (index << 2)]; // copying the column from the input to the temporary array.
			index += 1;
		}

		// multiplication operation starts from here.
		short tempValue = tempArray[0] ^ tempArray[1] ^ tempArray[2] ^ tempArray[3];
		index = 0;
		while (index < 4)
		{
			short value = ((tempArray[index] ^ tempArray[(index + 1) % 4]) << 1);
			if (value > 0xFF) value = (value ^ 0x1B) & 0xFF; // used as a compensator since we are now using x64 processors.
			p_output[time + (index << 2)] = tempArray[index] ^ tempValue ^ value;
			index += 1;
		}
		// end of emultiplication operation for a single column.

		time += 1;
	}
}
short multiply_number_number(short num1, short num2) 
{
	short result = 0x00, shifter = 0x01;
	if (shifter & num1) result = num2;
	while (!(shifter & 0x10))
	{
		shifter <<= 1;
		if (num2 & 0x80)
		{
			num2 <<= 1;
			num2 &= 0xFF;
			num2 ^= 0x1B;
		}
		else
		{
			num2 <<= 1;
		}
		if (shifter & num1) result ^= num2;
	}
	return result;
}
void inv_mix_column(short * p_output)
{
	int time = 0;
	short tempArray[4];
	short constant[16] = {
		0x0E, 0x0B, 0x0D, 0x09,
		0x09, 0x0E, 0x0B, 0x0D,
		0x0D, 0x09, 0x0E, 0x0B,
		0x0B, 0x0D, 0x09, 0x0E
	};
	while (time < 4)
	{
		// making a copy of the every column of the input
		for (int counter = 0; counter < 4; counter += 1)
		{
			tempArray[counter] = p_output[time + (counter << 2)];
			p_output[time + (counter << 2)] = 0;
		}

		// multiplication starts from here
		int index, row = 0;
		while (row < 4)
		{
			index = 0;
			while (index < 4)
			{
				p_output[time + (row << 2)] ^= multiply_number_number(constant[(row << 2)+ index], tempArray[index]);
				index += 1;
			}
			row += 1;
		}
		
		// end of multiplication
		time += 1;
	}
}

/*
Test case of mix_column. Just place the following in the main of this project.
short input[16] = {
0xf7, 0x05, 0x74, 0xd7,
0xab, 0x63, 0xbd, 0xb7,
0xad, 0x0c, 0x9e, 0x53,
0xf2, 0x0a, 0x9d, 0xa9
};
mix_column(input);
register short counter = 0;
while (counter < 16)
{
printf("%X\t", input[counter]);
if ((counter+1) % 4 == 0) printf("\r\n");
counter += 1;
}
return 0;

*/

/*
The following is a test code that should be place in the main function to test the inv_mix_column
hort input[16] = {
0x47, 0x40, 0xA3, 0x4C,
0x37, 0xD4, 0x70, 0x9F,
0x94, 0xE4, 0x3A, 0x42,
0xED, 0xA5, 0xA6, 0xBC
};
inv_mix_column(input);
register short counter = 0;
while (counter < 16)
{
printf("%X\t", input[counter]);
if ((counter+1) % 4 == 0) printf("\r\n");
counter += 1;
}
return 0;
*/